from django import template
from django import forms
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404

from native_tags.decorators import block
from genericview.views import HttpRedirectException, namespace_get
from pirateissues.models import Topic, Issue


'''
This file contains all of the tags that pertain to Issue objects, in order to fetch one
issue, a list of issues, or to add or update an issue.
'''


# this function assignment lets us reuse the same code block a bunch of places
get_namespace = namespace_get('pp_issue')


@block
def pp_get_issue(context, nodelist, *args, **kwargs):
    '''
    This block tag will grab an issue based on an object pair (str, obj_id) passed in
    as an argument (assigned to object), and will then put that issue into the context.

    The (str, obj_id) pair will be available via request.object.  In order to populate 
    request.objcect, the page in question should be accessed by via a url created as follows:

    {% url pp-page object="issue" id=issue.id template="filename.html" %}
    '''

    context.push()
    namespace = get_namespace(context)

    # this tag only works if a valid pair is assigned to the 'object=' argument
    object = kwargs.pop('object', None)
    if object is None or object[0] != "issue":
        raise ValueError("pp-get-issue tag requires that a (str, obj_id) pair be passed "
                             "to it assigned to the 'object=' argument, and that the str "
                             "be assigned the string value 'issue'.")
    
    namespace['issue'] = get_object_or_404(Issue,pk=object[1])
    output = nodelist.render(context)
    context.pop()

    return output


@block
def pp_issue_list(context, nodelist, *args, **kwargs):
    """
    This block tag will grab a list of issues.  It will optionally look for a topic or a 
    range of items in order to further refine the list.  In the future, the list might
    also be optionally generated as per a specific user.

    In order to generate a url that will provide range information to this tag via
    request.range, use a url tag of the following form:

    {% url pp-page template="filename.html" start=0 end=20 %}

    In this way, the tag can be invoked as follows:

    {% pp-issue-list topic=topic range=request.range %}
       Do stuff with {{ pp-issue.issue_list }}
    {% endpp-issue-list %}
    """

    context.push()
    namespace = get_namespace(context)

    #user  = kwargs.pop('user',  None)
    topic = kwargs.pop('topic', None)
    rng   = kwargs.pop('range', None)

    if isinstance(range, basestring):
        try:
            rng = range.strip("()").split(",")
            rng = (int(range[0]), int(range[1]))
        except:
            rng = None

        if not range or len(range) != 2:
            raise ValueException("The argument 'range=' to the pp-issue-list tag must be "
                                 "provided either in the form of an (int, int) pair, or "
                                 "as a string in the form of '(<int>, <int>)'.")
        
    #TODO: future functionality to get user-specific lists
    #however, it may be better to put this in the discovery module, to avoid cyclic dependency
    #if user:
    #    issue_list = pp_discovery.facade.issue_list_for_user(user, topic=topic, range=range)
    #else:

    if topic and isinstance(topic, Topic):
        issue_list = Issue.objects.filter(topic__id=topic.id).order_by('-pub_date')
    else:
        issue_list = Issue.objects.order_by('-pub_date')
    if range:
        issue_list = issue_list[range[0]:range[1]]

    namespace['issue_list'] = issue_list
    output = nodelist.render(context)
    context.pop()

    return output


@block
def pp_issue_form(context, nodelist, *args, **kwargs):
    '''
    This block tag can create or process forms either to create or to modify issues.
    Usage is as follows:

    {% pp-issue-form POST=request.POST path=request.path issue=pp-issue.issue %}
       Do stuff with {{ pp-issue.form }}.
    {% endpp-issue-form %}
    '''

    context.push()
    namespace = get_namespace(context)

    POST  = kwargs.get('POST', None)
    path  = kwargs.get('path', "")
    issue = kwargs.get('issue', None)

    if POST and POST.get("form_id") == "pp-issue-form":
        form = IssueForm(POST) if issue is None else IssueForm(POST, instance=issue)
        if form.is_valid():
            new_issue = form.save()
            raise HttpRedirectException(HttpResponseRedirect(path))
    else:
        form = IssueForm() if issue is None else IssueForm(instance=issue)

    namespace['form'] = form
    output = nodelist.render(context)
    context.pop()

    return output


class IssueForm(forms.ModelForm):
    '''
    This form is used to allow creation and modification of issue objects.  The form_id
    field is hidden and static and is used to allow the pp-issue-form tag to identify 
    whether the POST included with the submission pertains to issues or does not.

    By convention, the value of this hidden field should be the same as the tag that
    will process the form.
    '''

    class Meta:
        model = Issue

    form_id = forms.CharField(widget=forms.HiddenInput(), initial="pp-issue-form")
